package com.redhat.auth.ejb.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.sql.DataSource;

import org.redhat.auth.security.data.DataModel;
import org.redhat.auth.security.user.UserDetailInfo;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;

import com.redhat.auth.core.DefaultPasswordEncoder;
import com.redhat.auth.core.PasswordEncoder;

//@Service("ramsDataModel")
@Stateless(name = "DataModelApplicationBean")
@Remote(DataModel.class)
@javax.interceptor.Interceptors(SpringEJBIntercepter.class)
public class DataModelApplicationImpl implements DataModel {

	/* JDBC 获取用户信息的SQL语句 */
	private String userSql;

	private String userPassword;

	/* JDBC 获取用户角色信息的SQL语句 */
	private String userRolesSql;

	/* JDBC 获取资源信息的SQL语句 */
	private String resourceSql;

	/* JDBC 测试用户名 */
	private String testUsername;

	/* JDBC 测试密码 */
	private String testPassword;

	private boolean allowTestUser;

	/** arrow data source **/
	private DataSource dataSource;

	private PasswordEncoder passwordEncoder;

	public DataModelApplicationImpl() {
		passwordEncoder = new DefaultPasswordEncoder();
	}

	public boolean validatePassword(String username, String password) {
		Connection connection = null;
		PreparedStatement statment = null;
		ResultSet rs = null;
		try {
			connection = getDataSource().getConnection();
			statment = connection.prepareStatement(userPassword);
			statment.setString(1, username);
			rs = statment.executeQuery();
			while (rs.next()) {
				return passwordEncoder.isPasswordValid(
						rs.getString("PASSWORD"), password);
			}
		} catch (Exception e) {
		} finally {
			closeResultSet(rs);
			closeStatement(statment);
			closeConnection(connection);
		}
		return false;
	}

	public UserDetailInfo getUserByName(String username) {
		/* 在配置启用测试用户时,允许在开发中，持有一个测试用户，此用户不受权限限制 */
		if (isAllowTestUser()) {
			if (username.equals(testUsername)) {
				Collection<GrantedAuthority> atts = new ArrayList<GrantedAuthority>();
				UserDetailInfo user = new UserDetailInfo(testUsername,
						testPassword, true, true, true, true, atts);
				user.setTestUser(true);
				return user;
			}
		}
		return getUserInfoByName(username);
	}

	private UserDetailInfo getUserInfoByName(String name) {
		Connection connection = null;
		UserDetailInfo user = null;
		PreparedStatement statment = null;
		ResultSet rs = null;
		try {
			connection = getDataSource().getConnection();
			statment = connection.prepareStatement(userSql);
			statment.setString(1, name);
			rs = statment.executeQuery();
			while (rs.next()) {
				Map<String, Collection<ConfigAttribute>> roleEntityMap = getRoleEntityMap(name);
				Collection<GrantedAuthority> atts = getGrantedAuthority(roleEntityMap);
				//附加属性更新
				user = new UserDetailInfo(rs.getString("USERNAME"), rs
						.getString("PASSWORD"), true, true, true, true, atts);
				user.setDescription(rs.getString("DESCRIPTION"));
				user.setEmail(rs.getString("EMAIL"));
				user.setPasswordLastUpdateDate(rs
						.getDate("PASSWORD_LAST_UPDATE_DATE"));
				user.setRealName(rs.getString("REAL_NAME"));
				user.setRegistryDate(rs.getDate("REGISTRY_DATE"));
				user.setRoleEntityMap(roleEntityMap);
				break;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			closeResultSet(rs);
			closeStatement(statment);
			closeConnection(connection);
		}
		return user;
	}

	private Collection<GrantedAuthority> getGrantedAuthority(
			Map<String, Collection<ConfigAttribute>> roleEntityMap) {
		Set<GrantedAuthority> set = new HashSet<GrantedAuthority>();
		for (Entry<String, Collection<ConfigAttribute>> entry : roleEntityMap
				.entrySet()) {
			for (ConfigAttribute ca : entry.getValue()) {
				set.add(new GrantedAuthorityImpl(ca.getAttribute()));
			}
		}
		return set;
	}

	private Map<String, Collection<ConfigAttribute>> getRoleEntityMap(
			String userName) {
		Map<String, Collection<ConfigAttribute>> map = new HashMap<String, Collection<ConfigAttribute>>();
		Connection connection = null;
		PreparedStatement statment = null;
		ResultSet rs = null;
		try {
			connection = getDataSource().getConnection();
			statment = connection.prepareStatement(resourceSql);
			statment.setString(1, userName);
			rs = statment.executeQuery();
			while (rs.next()) {
				String url = rs.getString("URL");
				String roleName = rs.getString("ROLE");
				if (!roleName.startsWith("ROLE_")) {
					roleName = "ROLE_" + roleName;
				}
				if (map.containsKey(url)) {
					ConfigAttribute ca = new SecurityConfig(roleName);
					Collection<ConfigAttribute> collection = map.get(url);
					collection.add(ca);
					map.put(url, collection);
				} else {
					ConfigAttribute ca = new SecurityConfig(roleName);
					Collection<ConfigAttribute> collection = new HashSet<ConfigAttribute>();
					collection.add(ca);
					map.put(url, collection);
				}
			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
		} finally {
			closeResultSet(rs);
			closeStatement(statment);
			closeConnection(connection);
		}
		return map;
	}

	//	/**
	//	 * 返回数据库配置的资源保护
	//	 */
	//	public Map<String, Collection<ConfigAttribute>> getResource() {
	//		try {
	//			return getResourceByDataSource();
	//		} catch (Exception e) {
	//			throw new RuntimeException(e);
	//		}
	//	}
	//
	//	public UserDetailInfo getUserByName(String username) {
	//		/* 在配置启用测试用户时,允许在开发中，持有一个测试用户，此用户不受权限限制 */
	//		if (isAllowTestUser()) {
	//			if (username.equals(testUsername)) {
	//				Collection<GrantedAuthority> atts = new ArrayList<GrantedAuthority>();
	//				UserDetailInfo user = new UserDetailInfo(testUsername,
	//						testPassword, true, true, true, true, atts);
	//				user.setTestUser(true);
	//				return user;
	//			}
	//		}
	//		return getUserInfoByName(username);
	//	}
	//
	//	private Map<String, Collection<ConfigAttribute>> getResourceByDataSource()
	//			throws Exception {
	//		if (dataSource == null) {
	//			return null;
	//		}
	//		return getResourceByConnection(dataSource.getConnection());
	//	}
	//
	//	private Map<String, Collection<ConfigAttribute>> getResourceByConnection(
	//			Connection connection) throws Exception {
	//		Map<String, Collection<ConfigAttribute>> resources = new HashMap<String, Collection<ConfigAttribute>>();
	//		Statement statment = null;
	//		ResultSet rs = null;
	//		try {
	//			statment = connection.createStatement();
	//			rs = statment.executeQuery(resourceSql);
	//			while (rs.next()) {
	//				String url = rs.getString("URL");
	//				String roleName = rs.getString("ROLE");
	//				if (!roleName.startsWith("ROLE_")) {
	//					roleName = "ROLE_" + roleName;
	//				}
	//				if (resources.containsKey(url)) {
	//					ConfigAttribute ca = new SecurityConfig(roleName);
	//					Collection<ConfigAttribute> collection = resources.get(url);
	//					collection.add(ca);
	//					resources.put(url, collection);
	//				} else {
	//					ConfigAttribute ca = new SecurityConfig(roleName);
	//					Collection<ConfigAttribute> collection = new ArrayList<ConfigAttribute>();
	//					collection.add(ca);
	//					resources.put(url, collection);
	//				}
	//			}
	//		} finally {
	//			closeResultSet(rs);
	//			closeStatement(statment);
	//			closeConnection(connection);
	//		}
	//		return resources;
	//	}
	//
	//	/**
	//	 * 获取用户信息，以JDBC方式
	//	 */
	//	private UserDetailInfo getUserInfoByName(String name) {
	//		try {
	//			return getUserInfoByNameByDataSource(name);
	//		} catch (Exception e) {
	//			throw new RuntimeException(e);
	//		}
	//	}
	//
	//	private UserDetailInfo getUserInfoByNameByDataSource(String name)
	//			throws Exception {
	//		if (dataSource == null) {
	//			return null;
	//		}
	//		return getUserInfoByNameByConnection(name, dataSource.getConnection());
	//	}
	//
	//	private UserDetailInfo getUserInfoByNameByConnection(String name,
	//			Connection connection) throws Exception {
	//		UserDetailInfo user = null;
	//		PreparedStatement statment = null;
	//		ResultSet rs = null;
	//		try {
	//			statment = connection.prepareStatement(userSql);
	//			statment.setString(1, name);
	//			rs = statment.executeQuery();
	//			while (rs.next()) {
	//				Collection<GrantedAuthority> atts = getRolesByConnection(
	//						dataSource.getConnection(), name);
	//				//附加属性更新
	//				user = new UserDetailInfo(rs.getString("USERNAME"), rs
	//						.getString("PASSWORD"), true, true, true, true, atts);
	//				user.setDescription(rs.getString("DESCRIPTION"));
	//				user.setEmail(rs.getString("EMAIL"));
	//				user.setPasswordLastUpdateDate(rs
	//						.getDate("PASSWORD_LAST_UPDATE_DATE"));
	//				user.setRealName(rs.getString("REAL_NAME"));
	//				user.setRegistryDate(rs.getDate("REGISTRY_DATE"));
	//			}
	//		} finally {
	//			closeResultSet(rs);
	//			closeStatement(statment);
	//			closeConnection(connection);
	//		}
	//		return user;
	//	}
	//
	//	/**
	//	 * 获取一个用户的所有角色
	//	 * 
	//	 * @param username
	//	 * @return
	//	 */
	//	private Collection<GrantedAuthority> getRolesByConnection(
	//			Connection connection, String name) throws Exception {
	//		Collection<GrantedAuthority> atts = new ArrayList<GrantedAuthority>();
	//		PreparedStatement statment = null;
	//		ResultSet rs = null;
	//		try {
	//			statment = connection.prepareStatement(userRolesSql);
	//			statment.setString(1, name);
	//			rs = statment.executeQuery();
	//			while (rs.next()) {
	//				String roleName = rs.getString("ROLE_NAME");
	//				if (!roleName.startsWith("ROLE_")) {
	//					roleName = "ROLE_" + roleName;
	//				}
	//				GrantedAuthority auth1 = new GrantedAuthorityImpl(roleName);
	//				atts.add(auth1);
	//			}
	//		} finally {
	//			closeResultSet(rs);
	//			closeStatement(statment);
	//			closeConnection(connection);
	//		}
	//		return atts;
	//	}

	private static void closeConnection(Connection conn) {
		try {
			conn.close();
		} catch (Exception e) {
		}
	}

	private static void closeResultSet(ResultSet resultSet) {
		try {
			resultSet.close();
		} catch (Exception e) {
		}
	}

	private static void closeStatement(Statement stmt) {
		try {
			stmt.close();
		} catch (Exception e) {
		}
	}

	public String getUserSql() {
		return userSql;
	}

	public void setUserSql(String userSql) {
		this.userSql = userSql;
	}

	public String getUserRolesSql() {
		return userRolesSql;
	}

	public void setUserRolesSql(String userRolesSql) {
		this.userRolesSql = userRolesSql;
	}

	public String getTestUsername() {
		return testUsername;
	}

	public void setTestUsername(String testUsername) {
		this.testUsername = testUsername;
	}

	public String getTestPassword() {
		return testPassword;
	}

	public void setTestPassword(String testPassword) {
		this.testPassword = testPassword;
	}

	public String getResourceSql() {
		return resourceSql;
	}

	public void setResourceSql(String resourceSql) {
		this.resourceSql = resourceSql;
	}

	public boolean isAllowTestUser() {
		return allowTestUser;
	}

	public void setAllowTestUser(boolean allowTestUser) {
		this.allowTestUser = allowTestUser;
	}

	public DataSource getDataSource() {
		return dataSource;
	}

	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	public String getUserPassword() {
		return userPassword;
	}

	public void setUserPassword(String userPassword) {
		this.userPassword = userPassword;
	}

	public PasswordEncoder getPasswordEncoder() {
		return passwordEncoder;
	}

	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
		this.passwordEncoder = passwordEncoder;
	}

}
